use std::fmt;

use from_pest::FromPest;
use pest::iterators;
use pest_ast::FromPest;
use tracing::{debug, trace};

use crate::ast_define::Rule;

// * 线性运算符
#[derive(Debug, PartialEq)]
pub enum LinearOperator {
    PLUS(PLUS),
    MINUS(MINUS),
}

impl<'pest> FromPest<'pest> for LinearOperator {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 LinearOperator");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in LinearOperator:\n{pair:#?}");
        let Rule::LinearOperator = pair.as_rule() else {
            trace!("\n{:#?} != Rule::LinearOperator", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::PLUS => Ok(LinearOperator::PLUS(PLUS)),
            Rule::MINUS => Ok(LinearOperator::MINUS(MINUS)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for LinearOperator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            LinearOperator::PLUS(this) => write!(f, "{this}"),
            LinearOperator::MINUS(this) => write!(f, "{this}"),
        }
    }
}

// * 指数运算符
#[derive(Debug, PartialEq)]
pub enum ExponentOperator {
    MUL(MUL),
    DIV(DIV),
    MOD(MOD),
}

impl<'pest> FromPest<'pest> for ExponentOperator {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 ExponentOperator");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in ExponentOperator:\n{pair:#?}");
        let Rule::ExponentOperator = pair.as_rule() else {
            trace!("\n{:#?} != Rule::ExponentOperator", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::MUL => Ok(ExponentOperator::MUL(MUL)),
            Rule::DIV => Ok(ExponentOperator::DIV(DIV)),
            Rule::MOD => Ok(ExponentOperator::MOD(MOD)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for ExponentOperator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ExponentOperator::MUL(this) => write!(f, "{this}"),
            ExponentOperator::DIV(this) => write!(f, "{this}"),
            ExponentOperator::MOD(this) => write!(f, "{this}"),
        }
    }
}

// * 单目运算符
#[derive(Debug, PartialEq)]
pub enum UnaryOperator {
    PLUS(PLUS),
    MINUS(MINUS),
    NOT(NOT),
}

impl<'pest> FromPest<'pest> for UnaryOperator {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 UnaryOperator");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in UnaryOperator:\n{pair:#?}");
        let Rule::UnaryOperator = pair.as_rule() else {
            trace!("\n{:#?} != Rule::UnaryOperator", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::PLUS => Ok(UnaryOperator::PLUS(PLUS)),
            Rule::MINUS => Ok(UnaryOperator::MINUS(MINUS)),
            Rule::NOT => Ok(UnaryOperator::NOT(NOT)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for UnaryOperator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UnaryOperator::PLUS(this) => write!(f, "{this}"),
            UnaryOperator::MINUS(this) => write!(f, "{this}"),
            UnaryOperator::NOT(this) => write!(f, "{this}"),
        }
    }
}

// * 相等性运算符
#[derive(Debug, PartialEq)]
pub enum EqualityOperator {
    EQ(EQ),
    NEQ(NEQ),
}

impl<'pest> FromPest<'pest> for EqualityOperator {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 EqualityOperator");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in EqualityOperator:\n{pair:#?}");
        let Rule::EqualityOperator = pair.as_rule() else {
            trace!("\n{:#?} != Rule::EqualityOperator", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::EQ => Ok(EqualityOperator::EQ(EQ)),
            Rule::NEQ => Ok(EqualityOperator::NEQ(NEQ)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for EqualityOperator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EqualityOperator::EQ(this) => write!(f, "{this}"),
            EqualityOperator::NEQ(this) => write!(f, "{this}"),
        }
    }
}

// * 关系运算符
#[derive(Debug, PartialEq)]
pub enum RelationOperator {
    LE(LE),
    GE(GE),
    LT(LT),
    GT(GT),
}

impl<'pest> FromPest<'pest> for RelationOperator {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 RelationOperator");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in RelationOperator:\n{pair:#?}");
        let Rule::RelationOperator = pair.as_rule() else {
            trace!("\n{:#?} != Rule::RelationOperator", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::LE => Ok(RelationOperator::LE(LE)),
            Rule::GE => Ok(RelationOperator::GE(GE)),
            Rule::LT => Ok(RelationOperator::LT(LT)),
            Rule::GT => Ok(RelationOperator::GT(GT)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

impl fmt::Display for RelationOperator {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RelationOperator::LE(this) => write!(f, "{this}"),
            RelationOperator::GE(this) => write!(f, "{this}"),
            RelationOperator::LT(this) => write!(f, "{this}"),
            RelationOperator::GT(this) => write!(f, "{this}"),
        }
    }
}

// ?运算符 15个
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::EQ))]
pub struct EQ;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::NEQ))]
pub struct NEQ;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::LE))]
pub struct LE;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::GE))]
pub struct GE;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::AND))]
pub struct AND;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::OR))]
pub struct OR;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::PLUS))]
pub struct PLUS;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::MINUS))]
pub struct MINUS;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::MUL))]
pub struct MUL;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::DIV))]
pub struct DIV;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::MOD))]
pub struct MOD;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::ASSIGN))]
pub struct ASSIGN;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::LT))]
pub struct LT;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::GT))]
pub struct GT;

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::NOT))]
pub struct NOT;

impl fmt::Display for EQ {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "==")
    }
}
impl fmt::Display for NEQ {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "!=")
    }
}
impl fmt::Display for LE {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<=")
    }
}
impl fmt::Display for GE {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, ">=")
    }
}
impl fmt::Display for AND {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "&&")
    }
}
impl fmt::Display for OR {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "||")
    }
}
impl fmt::Display for PLUS {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "+")
    }
}
impl fmt::Display for MINUS {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "-")
    }
}
impl fmt::Display for MUL {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "*")
    }
}
impl fmt::Display for DIV {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "/")
    }
}
impl fmt::Display for MOD {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "%")
    }
}
impl fmt::Display for ASSIGN {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "=")
    }
}
impl fmt::Display for LT {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<")
    }
}
impl fmt::Display for GT {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, ">")
    }
}
impl fmt::Display for NOT {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "!")
    }
}
